//因为时间和选材的缘故，代码十分冗长且复杂，因为采用随机数的原理，程序运行需要较长的时间，而且会有一个小bug
//明天考高数，最近两天事情也多，实在改不动了，希望高数考试没事
//还有这个是用vs2019写的，用2010运行可能会有很多问题
#include <stdio.h>
#include <conio.h>
#include <graphics.h>
#include <math.h>
#include <time.h>
#define Height 800
#define Width 800

int num = 1;//画圆的个数
int sign;
int length = 600;//大三角的边长
//大三角的坐标数据
int top[2] = { Width / 2, 100 };
int bottom_L[2] = { Width / 2 - length / 2, 100 + length / 2 * sqrt(3) };
int bottom_R[2] = { Width / 2 + length / 2,  100 + length / 2 * sqrt(3) };

//所画圆的结构体变量
struct circle
{
	int x;
	int y;
	int r;
}Circle[100];

void startup()//初始化
{
	initgraph(Width, Height);
	setbkcolor(WHITE);
	cleardevice();
	srand(time(NULL));
	//初始化最大圆的数据
	Circle[0].x = top[0];
	Circle[0].y = top[1] + sqrt(3) / 3 * length;
	Circle[0].r = sqrt(3) / 6 * length;
}

float k(float x1, float y1, float x2, float y2)
{
	return (y2 - y1) / (x2 - x1);
}//求直线斜率

float b(float x1, float y1, float x2, float y2)
{
	return y1 - k(x1, y1, x2, y2) * x1;
}//求直线竖截距

void randnum()//随机设定圆的大小位置
{
	if (num <= 12)//确定新生成圆所切大圆的序号
		sign = (num - 1) / 3;
	else
		sign = 4 + (num - 13) / 3 * 3;
	Circle[num].x = rand() % (bottom_R[0] - bottom_L[0]) + bottom_L[0];
	Circle[num].y = rand() % (bottom_L[1]) + top[1];
	if (num % 3 != 0 || num == 3 || num >= 22)
		Circle[num].r = rand() % Circle[(num - 1) / 3].r;
	else//求对称圆的坐标
	{
		float line_k = k(Circle[sign].x, Circle[sign].y, Circle[0].x, Circle[0].y);
		float line_b = b(Circle[sign].x, Circle[sign].y, Circle[0].x, Circle[0].y);
		Circle[num].r = Circle[num - 1].r;
		if (Circle[sign].x == Circle[0].x)
		{
			Circle[num].x = Width - Circle[num - 1].x;
			Circle[num].y = Circle[num - 1].y;
		}
		else
		{
			Circle[num].x = (Circle[num - 1].x * (1 - line_k * line_k) + 2 * line_k * Circle[num - 1].y - 2 * line_k * line_b) / (line_k * line_k + 1);
			Circle[num].y = (Circle[num - 1].y * (line_k * line_k - 1) + 2 * line_b + 2 * line_k * Circle[num - 1].x) / (line_k * line_k + 1);
		}
	}
}

float distPoint(float x1, float y1, float x2, float y2)//求两点距离
{
	return sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));
}

float area(float a, float b, float c)//求三角形面积
{
	float p = (a + b + c) / 2;
	return sqrt(p * (p - a) * (p - b) * (p - c));
}

float distPointToLine(float point_x, float point_y, float line_x1, float line_y1, float line_x2, float line_y2)//求点到直线距离
{
	float S = area(distPoint(point_x, point_y, line_x1, line_y1),
		distPoint(point_x, point_y, line_x2, line_y2),
		distPoint(line_x1, line_y1, line_x2, line_y2));
	return S / distPoint(line_x1, line_y1, line_x2, line_y2) * 2;
}

bool isCirclelineOk()//判断圆与线是否相切
{
	bool judge1 = fabs(distPointToLine(Circle[num].x, Circle[num].y, top[0], top[1], bottom_L[0], bottom_L[1]) - (double)Circle[num].r) < 1;
	bool judge2 = fabs(distPointToLine(Circle[num].x, Circle[num].y, top[0], top[1], bottom_R[0], bottom_R[1]) - (double)Circle[num].r) < 1;
	bool judge3 = fabs(distPointToLine(Circle[num].x, Circle[num].y, bottom_R[0], bottom_R[1], bottom_L[0], bottom_L[1]) - (double)Circle[num].r) < 1;
	if (num >= 22)
		if (judge1 || judge2 || judge3)
			return true;
		else
			return false;
	if (num <= 3 || (num - 1) % 3 == 0)
	{
		if (judge1 && judge2 || judge1 && judge3 || judge2 && judge3)
			return true;
	}
	else
	{
		if (judge1 || judge2 || judge3)
			return true;
	}
	return false;
}

bool isTwoCircle(int n, int circle1, int circle2)
{
	if (fabs(distPoint(Circle[circle1].x, Circle[circle1].y, Circle[num].x, Circle[num].y) - (Circle[circle1].r + Circle[num].r)) < 1
		&& fabs(distPoint(Circle[circle2].x, Circle[circle2].y, Circle[num].x, Circle[num].y) - (Circle[circle2].r + Circle[num].r)) < 1)
		return true;
	return false;
}

bool isCircleCircleOk()//判断新圆与已有圆是否相切
{
	for (int i = 0; i < num; i++)
	{
		if (fabs(Circle[i].x - Circle[num].x) < Circle[i].r
			&& fabs(Circle[i].y - Circle[num].y) < Circle[i].r)
			return false;
	}
	if (num <= 3 || (num - 1) % 3 == 0)
	{
		if (fabs(distPoint(Circle[sign].x, Circle[sign].y, Circle[num].x, Circle[num].y) - (Circle[sign].r + Circle[num].r)) < 1)
			return true;
	}
	else
	{
		if (isTwoCircle(num,sign,(sign-1)/3))
			return true;
	}
	return false;
}

void show()
{
	POINT pts[] = { {top[0], top[1]},{bottom_L[0], bottom_L[1]},{bottom_R[0], bottom_R[1]} };//设置等边三角形坐标
	setlinecolor(BLACK);
	polygon(pts, 3);//画等边三角形
	circle(Circle[0].x, Circle[0].y, Circle[0].r);
	while (num < 28)
	{
		randnum();
		if (num < 22)
		{
			if (isCirclelineOk() && isCircleCircleOk() || (num % 3 == 0 && num != 3))
			{
				circle(Circle[num].x, Circle[num].y, Circle[num].r);
				num++;
			}
		}
		else//填充小圆
		{
			int i = 5, count = 0;
			while (count<6)
			{
				if (i % 3 == 1 && i < 13)
					i++;
				randnum();
				if (isTwoCircle(num, i, 0) && isCirclelineOk())
				{
					circle(Circle[num].x, Circle[num].y, Circle[num].r);
					num++; count++; i++;
				}
				if (count == 6&&i<22)
				{
					i = 22; count = 0;
				}
			}
		}
	}
}

int main()
{
	startup();
	show();
	_getch();
	return 0;
}